home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / uupc11ys.zip / UUCICO / DCPGPKT.C < prev    next >
C/C++ Source or Header  |  1993-04-13  |  59KB  |  1,680 lines

  1. /*
  2.    d c p g p k t . c
  3.  
  4.    Revised edition of dcp
  5.  
  6.    Stuart Lynne May/87
  7.  
  8.    Copyright (c) Richard H. Lamb 1985, 1986, 1987
  9.    Changes Copyright (c) Stuart Lynne 1987
  10.    Changes Copyright (c) Andrew H. Derbyshire 1989
  11.    Changes Copyright (c) Kendra Electronic Wonderworks 1990-1993
  12.  
  13.    Maintenance notes:
  14.  
  15.    25Aug87 - Allow for up to 7 windows - Jal
  16.    01Nov87 - those strncpy's should really be memcpy's! - Jal
  17.    11Sep89 - Raise TimeOut to 15 - ahd
  18.    30Apr90 - Add Jordon Brown's fix for short packet retries.
  19.              Reduce retry limit to 20                             ahd
  20.    22Jul90 - Change error retry limit from per host to per
  21.              packet.                                              ahd
  22.    22Jul90 - Add error message for number of retries exceeded     ahd
  23.    08Sep90 - Drop memmove to memcpy change supplied by Jordan
  24.              Brown, MS 6.0 and Turbo C++ agree memmove insures
  25.              no overlap
  26. */
  27.  
  28. /*
  29.  *      $Id: DCPGPKT.C 1.12 1993/04/13 03:19:45 ahd Exp $
  30.  *
  31.  *      $Log: DCPGPKT.C $
  32.  * Revision 1.12  1993/04/13  03:19:45  ahd
  33.  * Only perform copy to gspkt if input to gsendpkt is non-null
  34.  *
  35.  * Revision 1.11  1993/04/13  03:00:05  ahd
  36.  * Correct gspkt declare
  37.  *
  38.  * Revision 1.10  1993/04/13  02:26:30  ahd
  39.  * Move buffers to FAR memory
  40.  *
  41.  * Revision 1.9  1993/04/05  04:32:19  ahd
  42.  * Allow unique send and receive packet sizes
  43.  *
  44.  * Revision 1.8  1993/03/06  23:04:54  ahd
  45.  * Make state names more descriptive
  46.  *
  47.  * Revision 1.7  1992/11/21  05:55:11  ahd
  48.  * Use single bit field for gopenpk flag bits, add debugging info
  49.  *
  50.  * Revision 1.6  1992/11/20  12:38:39  ahd
  51.  * Add additional flags to avoid prematurely ending init sequence
  52.  *
  53.  * Revision 1.5  1992/11/19  03:00:29  ahd
  54.  * drop rcsid
  55.  *
  56.  * Revision 1.4  1992/11/17  13:45:37  ahd
  57.  * Add comments from Ian Talyor
  58.  *
  59.  * Revision 1.3  1992/11/16  02:10:27  ahd
  60.  * Rewrite protocol initialize to insure full exchange of packets
  61.  *
  62.  */
  63.  
  64.  
  65. /* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
  66.  
  67. /* 7-window "g" ptotocol */
  68.  
  69. /*--------------------------------------------------------------------*/
  70. /*    Thanks goes to John Gilmore for sending me a copy of Greg       */
  71. /*    Chesson's UUCP protocol description -- Obviously invaluable.    */
  72. /*    Thanks also go to Andrew Tannenbaum for the section on          */
  73. /*    Siding window protocols with a program example in his           */
  74. /*    "Computer Networks" book.                                       */
  75. /*--------------------------------------------------------------------*/
  76.  
  77. /*--------------------------------------------------------------------*/
  78. /*                        System include files                        */
  79. /*--------------------------------------------------------------------*/
  80.  
  81. #include <stdio.h>
  82. #include <string.h>
  83. #include <time.h>
  84. #include <stdlib.h>
  85. #include <ctype.h>
  86.  
  87. #ifdef __TURBOC__
  88. #include <mem.h>
  89. #include <alloc.h>
  90. #else
  91. #include <malloc.h>
  92. #endif
  93.  
  94. /*--------------------------------------------------------------------*/
  95. /*                    UUPC/extended include files                     */
  96. /*--------------------------------------------------------------------*/
  97.  
  98. #include "lib.h"
  99. #include "dcp.h"
  100. #include "dcpsys.h"
  101. #include "dcpgpkt.h"
  102. #include "hostable.h"
  103. #include "security.h"
  104. #include "ulib.h"
  105. #include "modem.h"
  106. #include "catcher.h"
  107.  
  108. /*--------------------------------------------------------------------*/
  109. /*                           Local defines                            */
  110. /*--------------------------------------------------------------------*/
  111.  
  112. #define PKTSIZE   MAXPACK
  113. #define MINPKT    32
  114.  
  115. #define HDRSIZE   6
  116. #define MAXTRY 4
  117.  
  118. #ifndef GDEBUG
  119. #define GDEBUG 4
  120. #endif
  121.  
  122. /*--------------------------------------------------------------------*/
  123. /*    Control whether some buffers are placed outside the default     */
  124. /*    data segment                                                    */
  125. /*--------------------------------------------------------------------*/
  126.  
  127. #ifdef __TURBOC__
  128. #define memavail  coreleft
  129. #else
  130. #define memavail  stackavail
  131. #endif
  132.  
  133. /*--------------------------------------------------------------------*/
  134. /*                     g-packet type definitions                      */
  135. /*--------------------------------------------------------------------*/
  136.  
  137. #define DATA   0
  138. #define CLOSE  1
  139. #define NAK    2
  140. #define SRJ    3
  141. #define ACK    4
  142. #define INITC  5
  143. #define INITB  6
  144. #define INITA  7
  145.  
  146. #define POK    -1
  147.  
  148. #define MAXWINDOW 7
  149. #define NBUF   8              /* always SAME as MAXSEQ ? */
  150. #define MAXSEQ 8
  151.  
  152. typedef enum {
  153.       I_EMPTY,
  154.       I_ERROR,
  155.       I_RESTART,
  156.       I_CALLEE,
  157.       I_CALLER,
  158.       I_GRPACK,
  159.       I_INITA_RECV,
  160.       I_INITA_SEND,
  161.       I_INITB_RECV,
  162.       I_INITB_SEND,
  163.       I_INITC_RECV,
  164.       I_INITC_SEND,
  165.       I_COMPLETE
  166.       } I_STATE;
  167.  
  168. #define between(a,b,c) ((a<=b && b<c) || \
  169.                         (c<a && a<=b) || \
  170.                         (b<c && c<a))
  171.  
  172. #define nextpkt(x)    ((x + 1) % MAXSEQ)
  173. #define nextbuf(x)    ((x + 1) % (nwindows+1))
  174.  
  175. /*--------------------------------------------------------------------*/
  176. /*                 Handle 16 bit vs. 32 bit compilers                 */
  177. /*--------------------------------------------------------------------*/
  178.  
  179. #ifdef WIN32
  180. #define UUFAR
  181. #define MEMSET(p,c,l)  memset(p,c,l)
  182. #define MEMCPY(t,s,l)  memcpy(t,s,l)
  183. #define MEMMOVE(t,s,l) memmove(t,s,l)
  184. #else
  185. #ifdef __TURBOC__
  186. #define UUFAR far
  187. #else
  188. #define UUFAR _far
  189. #endif
  190. #define MEMSET(p,c,l)  _fmemset(p,c,l)
  191. #define MEMCPY(t,s,l)  _fmemcpy(t,s,l)
  192. #define MEMMOVE(t,s,l) _fmemmove(t,s,l)
  193. #endif
  194.  
  195. /*--------------------------------------------------------------------*/
  196. /*              Global variables for packet definitions               */
  197. /*--------------------------------------------------------------------*/
  198.  
  199. currentfile();
  200.  
  201. static short rwl, swl, swu, rwu, irec, lazynak;
  202. static unsigned short nbuffers;
  203. static short rbl, sbl, sbu;
  204. static INTEGER nerr;
  205. static unsigned short outlen[NBUF], inlen[NBUF], xmitlen[NBUF];
  206. static boolean arrived[NBUF];
  207. static size_t nwindows;
  208.  
  209. static char UUFAR outbuf[NBUF][MAXPACK];
  210. static char UUFAR inbuf[NBUF][MAXPACK];
  211. static time_t ftimer[NBUF];
  212. static short timeouts, outsequence, naksin, naksout, screwups;
  213. static short reinit, shifts, badhdr, resends;
  214. static unsigned char *grpkt = NULL;
  215. #ifndef WIN32
  216. static char *gspkt = NULL;
  217. #endif
  218. static boolean variablepacket;  /* "v" or in modem file              */
  219.  
  220. /*--------------------------------------------------------------------*/
  221. /*                    Internal function prototypes                    */
  222. /*--------------------------------------------------------------------*/
  223.  
  224. static short initialize(const boolean caller, const char protocol );
  225.  
  226. static short  gmachine(const short timeout);
  227.  
  228. static void gspack(short  type,
  229.                    short  yyy,
  230.                    short  xxx,
  231.                    short  len,
  232.                    unsigned short xmit,
  233.                    char UUFAR *data);
  234.  
  235. static short  grpack(short  *yyy,
  236.                    short  *xxx,
  237.                    short  *len,
  238.                    char UUFAR *data,
  239.                    const short timeout);
  240.  
  241. static void gstats( void );
  242.  
  243. static unsigned short checksum(char *data, short len);
  244.  
  245. /****************** SUB SUB SUB PACKET HANDLER ************/
  246.  
  247. /*--------------------------------------------------------------------*/
  248. /*    g o p e n p k                                                   */
  249. /*                                                                    */
  250. /*    Initialize processing for protocol                              */
  251. /*--------------------------------------------------------------------*/
  252.  
  253. short Gopenpk(const boolean caller)
  254. {
  255.    return initialize(caller , 'G');
  256. } /* Gopenpk */
  257.  
  258. /*--------------------------------------------------------------------*/
  259. /*    v o p e n p k                                                   */
  260. /*                                                                    */
  261. /*    Initialize processing for protocol                              */
  262. /*--------------------------------------------------------------------*/
  263.  
  264. short vopenpk(const boolean caller)
  265. {
  266.    return initialize(caller, 'v');
  267. } /* vopenpk */
  268.  
  269. /*--------------------------------------------------------------------*/
  270. /*    g o p e n p k                                                   */
  271. /*                                                                    */
  272. /*    Initialize processing for protocol                              */
  273. /*--------------------------------------------------------------------*/
  274.  
  275. short gopenpk(const boolean caller)
  276. {
  277.    return initialize(caller, 'g');
  278. } /* vopenpk */
  279.  
  280. /*--------------------------------------------------------------------*/
  281. /*    i n i t i a l i z e                                             */
  282. /*                                                                    */
  283. /*    Initialize processing for protocol                              */
  284. /*--------------------------------------------------------------------*/
  285.  
  286. static short initialize(const boolean caller, const char protocol )
  287. {
  288.    short i, xxx, yyy, len, maxwindows;
  289.  
  290. #define B_SENT_INITA 0x01
  291. #define B_SENT_INITB 0x02
  292. #define B_SENT_INITC 0x04
  293. #define B_RECV_INITA 0x10
  294. #define B_RECV_INITB 0x20
  295. #define B_RECV_INITC 0x40
  296. #define B_INITA (B_SENT_INITA | B_RECV_INITA)
  297. #define B_INITB (B_SENT_INITB | B_RECV_INITB)
  298. #define B_INITC (B_SENT_INITC | B_RECV_INITC)
  299.  
  300.    short  flags = 0x00;   /* Init state flags, as defined above  */
  301.  
  302.    I_STATE state;
  303.  
  304. /*--------------------------------------------------------------------*/
  305. /*    Read modem file values for the number of windows and packet     */
  306. /*    sizes                                                           */
  307. /*--------------------------------------------------------------------*/
  308.  
  309.    r_pktsize = s_pktsize = GetGPacket( MAXPACK, protocol );
  310.    maxwindows = GetGWindow(
  311.                      min( MAXWINDOW, RECV_BUF / (s_pktsize+HDRSIZE)),
  312.                      protocol);
  313.  
  314.    variablepacket = bmodemflag[MODEM_VARIABLEPACKET] || (protocol == 'v');
  315.  
  316.    grpkt = malloc( r_pktsize + HDRSIZE );
  317.  
  318. /*--------------------------------------------------------------------*/
  319. /*                     Initialize error counters                      */
  320. /*--------------------------------------------------------------------*/
  321.  
  322.    timeouts = outsequence = naksin = naksout = screwups =
  323.       shifts = badhdr = resends = reinit = 0;
  324.  
  325. /*--------------------------------------------------------------------*/
  326. /*                    Initialize proto parameters                     */
  327. /*--------------------------------------------------------------------*/
  328.  
  329.    nerr = nbuffers = 0;
  330.    sbl = swl = swu = sbu = 1;
  331.    rbl = rwl = 0;
  332.    nwindows = maxwindows;
  333.    rwu = nwindows - 1;
  334.  
  335.    for (i = 0; i < NBUF; i++)
  336.    {
  337.       ftimer[i] = 0;
  338.       arrived[i] = FALSE;
  339.    }
  340.  
  341. /*--------------------------------------------------------------------*/
  342. /*                          3-way handshake                           */
  343. /*--------------------------------------------------------------------*/
  344.  
  345. /*--------------------------------------------------------------------*/
  346. /*    The three-way handshake should be independent of who            */
  347. /*    initializes it, but it seems that some versions of uucico       */
  348. /*    assume that the caller sends first and the callee responds.     */
  349. /*    This only matters if we are the callee and the first packet     */
  350. /*    is garbled.  If we send a packet, the other side will assume    */
  351. /*    that we must have seen the packet they sent and will never      */
  352. /*    time out and send it again.  Therefore, if we are the callee    */
  353. /*    we don't send a packet the first time through the loop.         */
  354. /*    This can still fail, but should usually work, and, after        */
  355. /*    all, if the initialization packets are received correctly       */
  356. /*    there will be no problem no matter what we do.                  */
  357. /*                                                                    */
  358. /*    (The above quoted verbatim from Ian Taylor)                     */
  359. /*--------------------------------------------------------------------*/
  360.  
  361.    state = caller ? I_CALLER : I_CALLEE;
  362.  
  363. /*--------------------------------------------------------------------*/
  364. /*    Exchange initialization messages with the other system.         */
  365. /*                                                                    */
  366. /*    A problem:                                                      */
  367. /*                                                                    */
  368. /*    We send INITA; it gets received                                 */
  369. /*    We receive INITA                                                */
  370. /*    We send INITB; it gets garbled                                  */
  371. /*    We receive INITB                                                */
  372. /*                                                                    */
  373. /*    We have seen and sent INITB, so we start to send INITC.  The    */
  374. /*    other side as sent INITB but not seen it, so it times out       */
  375. /*    and resends INITB.  We will continue sending INITC and the      */
  376. /*    other side will continue sending INITB until both sides give    */
  377. /*    up and start again with INITA.                                  */
  378. /*                                                                    */
  379. /*    It might seem as though if we are sending INITC and receive     */
  380. /*    INITB, we should resend our INITB, but this could cause         */
  381. /*    infinite echoing of INITB on a long-latency line.  Rather       */
  382. /*    than risk that, I have implemented a fast drop-back             */
  383. /*    procedure.  If we are sending INITB and receive INITC, the      */
  384. /*    other side has gotten ahead of us.  We immediately fail and     */
  385. /*    begin again with INITA.  For the other side, if we are          */
  386. /*    sending INITC and see INITA, we also immediately fail back      */
  387. /*    to INITA.                                                       */
  388. /*                                                                    */
  389. /*    Unfortunately, this doesn't work for the other case, in         */
  390. /*    which we are sending INITB but the other side has not yet       */
  391. /*    seen INITA.  As far as I can see, if this happens we just       */
  392. /*    have to wait until we time out and resend INITA.                */
  393. /*                                                                    */
  394. /*    (The above also quoted verbatim from Ian Taylor; however, the   */
  395. /*    code and associated bugs are all Drew's)                        */
  396. /*--------------------------------------------------------------------*/
  397.  
  398. /*--------------------------------------------------------------------*/
  399. /*    A note about the games with the variable "flags", which is      */
  400. /*    bit twiddled alot below.  The statement below:                  */
  401. /*                                                                    */
  402. /*          flags = (flags & B_SENT_INITA) | B_RECV_INITA;            */
  403. /*                                                                    */
  404. /*    works to turn off all the bits in flags except B_SENT_INITA     */
  405. /*    if it was already on, and then turns on flag B_RECV_INITA.      */
  406. /*    We use statements like this to reset most of the flags at       */
  407. /*    once, leaving one or two bits on; this in turn allows us to     */
  408. /*    check in later states that the previous two states were the     */
  409. /*    expected ones.                                                  */
  410. /*                                                                    */
  411. /*    Likewise, the following statement:                              */
  412. /*                                                                    */
  413. /*          state = (flags & B_SENT_INITA) ?                          */
  414. /*                         I_INITB_SEND : I_INITA_SEND;               */
  415. /*                                                                    */
  416. /*    tests to see if B_SENT_INITA was already set, and return the    */
  417. /*    "true" condition (I_INITB_SEND) otherwise return the "false"    */
  418. /*    (I_INITA_SEND).                                                 */
  419. /*--------------------------------------------------------------------*/
  420.  
  421.  
  422.    while( state != I_COMPLETE )
  423.    {
  424.       printmsg(4, "gopenpk: I State = %2d, flag = 0x%02x",
  425.                (int) state, (int) flags);
  426.  
  427.       switch( state )
  428.       {
  429.  
  430. /*--------------------------------------------------------------------*/
  431. /*                          Receive a packet                          */
  432. /*--------------------------------------------------------------------*/
  433.  
  434.          case I_GRPACK:
  435.             switch (grpack(&yyy, &xxx, &len, NULL, M_gPacketTimeout ))
  436.             {
  437.  
  438.                case INITA:
  439.                   printmsg(5, "**got INITA");
  440.                   state = I_INITA_RECV;
  441.                   break;
  442.  
  443.                case INITB:
  444.                   printmsg(5, "**got INITB");
  445.                   state = I_INITB_RECV;
  446.                   break;
  447.  
  448.                case INITC:
  449.                   printmsg(5, "**got INITC");
  450.                   state = I_INITC_RECV;
  451.                   break;
  452.  
  453.                case EMPTY:
  454.                   printmsg(GDEBUG, "**got EMPTY");
  455.                   state = I_EMPTY;
  456.  
  457.                   if (bmodemflag[MODEM_CD] && !CD())
  458.                   {
  459.                      printmsg(0,"gopenpk: Modem carrier lost");
  460.                      return FAILED;
  461.                   }
  462.                   break;
  463.  
  464.                case CLOSE:
  465.                   printmsg(GDEBUG, "**got CLOSE");
  466.                   gspack(CLOSE, 0, 0, 0, 0, NULL);
  467.                   return FAILED;
  468.  
  469.                default:
  470.                   printmsg(GDEBUG, "**got SCREW UP");
  471.                   state = I_ERROR;
  472.                   break;
  473.             }
  474.  
  475.             if (bmodemflag[MODEM_CD] && !CD())
  476.             {
  477.                printmsg(0,"gopenpk: Modem carrier lost");
  478.                return FAILED;
  479.             }
  480.             break;
  481.  
  482. /*--------------------------------------------------------------------*/
  483. /*                         Initialize states                          */
  484. /*--------------------------------------------------------------------*/
  485.  
  486.          case I_CALLER:
  487.             state = I_INITA_SEND;
  488.             break;
  489.  
  490.          case I_CALLEE:
  491.             state = I_GRPACK;
  492.             break;
  493.  
  494. /*--------------------------------------------------------------------*/
  495. /*                  Process received or sent packets                  */
  496. /*--------------------------------------------------------------------*/
  497.  
  498.          case I_INITA_RECV:
  499.             if (yyy < (short) nwindows)
  500.             {
  501.                nwindows = yyy;
  502.                rwu = nwindows - 1;
  503.             }
  504.             flags = (flags & B_SENT_INITA) | B_RECV_INITA;
  505.             state = (flags & B_SENT_INITA) ? I_INITB_SEND : I_INITA_SEND;
  506.             break;
  507.  
  508.          case I_INITA_SEND:
  509.             gspack(INITA, 0, 0, 0, nwindows, NULL);
  510.             flags = (flags & B_RECV_INITA) | B_SENT_INITA;
  511.             state = I_GRPACK;
  512.             break;
  513.  
  514.          case I_INITB_RECV:
  515.             if ((flags & (B_RECV_INITA | B_SENT_INITA)) ==
  516.                          (B_RECV_INITA | B_SENT_INITA))
  517.             {
  518.                i = (short) 8 * (2 << (yyy+1));
  519.                if (i < (short) s_pktsize)
  520.                   s_pktsize = i;
  521.                flags = (flags & B_SENT_INITB) | B_RECV_INITB;
  522.                state = (flags & B_SENT_INITB) ? I_INITC_SEND : I_INITB_SEND;
  523.             } /* if */
  524.             else
  525.                state = I_RESTART;
  526.             break;
  527.  
  528.          case I_INITB_SEND:
  529.             gspack(INITB, 0, 0, 0, r_pktsize, NULL);
  530.                                        /* Data segment (packet) size    */
  531.             flags = (flags & (B_INITA | B_RECV_INITB)) | B_SENT_INITB;
  532.             state = I_GRPACK;
  533.             break;
  534.  
  535.          case I_INITC_RECV:
  536.             if ((flags & (B_RECV_INITB | B_SENT_INITB)) ==
  537.                            (B_RECV_INITB | B_SENT_INITB))
  538.             {
  539.                if (yyy < (short) nwindows)
  540.                {
  541.                   printmsg(0,"Unexpected INITC window size of %d",
  542.                              nwindows );
  543.                   nwindows = yyy;
  544.                   rwu = nwindows - 1;
  545.                }
  546.                flags = (flags & B_SENT_INITC) | B_RECV_INITC;
  547.                state = (flags & B_SENT_INITC) ? I_COMPLETE : I_INITC_SEND;
  548.             }
  549.             else
  550.                state = I_RESTART;
  551.             break;
  552.  
  553.          case I_INITC_SEND:
  554.             gspack(INITC, 0, 0, 0, nwindows, NULL);
  555.             flags = (flags & (B_INITB | B_RECV_INITC)) | B_SENT_INITC;
  556.             state = (flags & B_RECV_INITC) ? I_COMPLETE : I_GRPACK;
  557.             break;
  558.  
  559. /*--------------------------------------------------------------------*/
  560. /*                            Error states                            */
  561. /*--------------------------------------------------------------------*/
  562.  
  563.          case I_EMPTY:
  564.             timeouts++;
  565.             state = I_RESTART;
  566.             break;
  567.  
  568.          case I_ERROR:
  569.             screwups++;
  570.             state = I_RESTART;
  571.             break;
  572.  
  573.          case I_RESTART:
  574.             printmsg(2,"gopenpk: Restarting initialize sequence");
  575.             nerr++;
  576.             flags = 0x00;
  577.             state = I_INITA_SEND;
  578.             break;
  579.  
  580.       } /* switch */
  581.  
  582.       if ( terminate_processing )
  583.       {
  584.          printmsg(0,"gopenpk: Terminated by user");
  585.          return FAILED;
  586.       }
  587.  
  588.       if (nerr >= M_MaxErr)
  589.       {
  590.          remote_stats.errors += nerr;
  591.          nerr = 0;
  592.          printmsg(0,
  593.             "gopenpk: Consecutive error limit of %ld exceeded, "
  594.                      "%ld total errors",
  595.              (long) M_MaxErr, remote_stats.errors);
  596.          return(FAILED);
  597.       }
  598.    } /* while */
  599.  
  600. /*--------------------------------------------------------------------*/
  601. /*                    Allocate the needed buffers                     */
  602. /*--------------------------------------------------------------------*/
  603.  
  604.    grpkt = realloc( grpkt, r_pktsize + HDRSIZE );
  605.    checkref( grpkt );
  606.  
  607. #ifndef WIN32
  608.    gspkt = malloc( s_pktsize );
  609.    checkref( gspkt );
  610. #endif
  611.  
  612.    nerr = 0;
  613.    lazynak = 0;
  614.  
  615. #ifdef WIN32
  616.    printmsg(2,"%s packets, "
  617.               "Window size %d, "
  618.               "Receive packet %d\n, "
  619.               "Send packet %d\n",
  620.             variablepacket ? "Variable" : "Fixed",
  621.             nwindows,
  622.             r_pktsize,
  623.             s_pktsize );
  624. #else
  625.    printmsg(2,"%s packets, "
  626.               "Window size %d, "
  627.               "Receive packet %d, "
  628.               "Send packet %d, "
  629.               "Memory avail %u",
  630.             variablepacket ? "Variable" : "Fixed",
  631.             nwindows,
  632.             r_pktsize,
  633.             s_pktsize,
  634.             memavail());
  635. #endif
  636.  
  637.    return(OK); /* channel open */
  638.  
  639. } /*initialize*/
  640.  
  641. /*--------------------------------------------------------------------*/
  642. /*    g f i l e p k t                                                 */
  643. /*                                                                    */
  644. /*    Begin a file transfer (not used by "g" protocol)                */
  645. /*--------------------------------------------------------------------*/
  646.  
  647. short gfilepkt( void )
  648. {
  649.  
  650.    return OK;
  651.  
  652. } /* gfilepkt */
  653.  
  654. /*--------------------------------------------------------------------*/
  655. /*    g c l o s e p k                                                 */
  656. /*                                                                    */
  657. /*    Close packet machine                                            */
  658. /*--------------------------------------------------------------------*/
  659.  
  660. short gclosepk()
  661. {
  662.    unsigned short i;
  663.  
  664.    for (i = 0; i < MAXTRY; i++)
  665.    {
  666.       gspack(CLOSE, 0, 0, 0, 0, NULL);
  667.       if (gmachine(M_gPacketTimeout) == CLOSE)
  668.          break;
  669.    } /* for (i = 0; i < MAXTRY; i++) */
  670.  
  671. /*--------------------------------------------------------------------*/
  672. /*                        Release our buffers                         */
  673. /*--------------------------------------------------------------------*/
  674.  
  675.    free( grpkt );
  676.    grpkt = NULL;
  677.  
  678. #ifndef WIN32
  679.    free( gspkt );
  680.    gspkt = NULL;
  681. #endif
  682.  
  683. /*--------------------------------------------------------------------*/
  684. /*                Report the results of our adventures                */
  685. /*--------------------------------------------------------------------*/
  686.  
  687.    gstats();
  688.  
  689. /*--------------------------------------------------------------------*/
  690. /*                          Return to caller                          */
  691. /*--------------------------------------------------------------------*/
  692.  
  693.    return(0);
  694.  
  695. } /*gclosepk*/
  696.  
  697. /*--------------------------------------------------------------------*/
  698. /*    g s t a t s                                                     */
  699. /*                                                                    */
  700. /*    Report summary of errors for processing                         */
  701. /*--------------------------------------------------------------------*/
  702.  
  703. static void gstats( void )
  704. {
  705.    remote_stats.errors += nerr;
  706.    nerr = 0;
  707.    if ( remote_stats.errors || badhdr )
  708.    {
  709.       printmsg(0,
  710.          "%d time outs, %d port reinits, %d out of seq pkts, "
  711.          "%d NAKs rec, %d NAKs sent",
  712.             timeouts, reinit, outsequence, naksin, naksout);
  713.       printmsg(0,
  714.          "%d invalid pkt types, %d re-syncs, %d bad pkt hdrs, %d pkts resent",
  715.             screwups, shifts, badhdr, resends);
  716.    } /* if ( remote_stats.errors || shifts || badhdr ) */
  717. } /* gstats */
  718.  
  719. /*--------------------------------------------------------------------*/
  720. /*    g g e t p k t                                                   */
  721. /*                                                                    */
  722. /*    Gets no more than a packet's worth of data from                 */
  723. /*    the "packet I/O state machine".  May have to                    */
  724. /*    periodically run the packet machine to get some packets.        */
  725. /*                                                                    */
  726. /*    on input:   don't care                                          */
  727. /*    on return:  data+\0 and length in len.                          */
  728. /*                                                                    */
  729. /*    ret(0)   if all's well                                          */
  730. /*    ret(-1) if problems (failed)                                    */
  731. /*--------------------------------------------------------------------*/
  732.  
  733. short ggetpkt(char *data, short *len)
  734. {
  735.    short   retry = M_MaxErr;
  736.    time_t start;
  737. #ifdef _DEBUG
  738.    short savedebug = debuglevel;
  739. #endif
  740.  
  741.    irec = 1;
  742.    checkref( data );
  743.  
  744. /*--------------------------------------------------------------------*/
  745. /*                Loop to wait for the desired packet                 */
  746. /*--------------------------------------------------------------------*/
  747.  
  748.    time( &start );
  749.    while (!arrived[rbl] && retry)
  750.    {
  751.       if (gmachine(M_gPacketTimeout) != POK)
  752.          return(-1);
  753.  
  754.       if (!arrived[rbl] )
  755.       {
  756.          time_t now;
  757.          if (time( &now ) > (start + M_gPacketTimeout) )
  758.          {
  759. #ifdef _DEBUG
  760.             if ( debuglevel < 6 )
  761.                debuglevel = 6;
  762. #endif
  763.             printmsg(GDEBUG,
  764.                      "ggetpkt: Timeout %d waiting for inbound packet %d",
  765.                      M_MaxErr - --retry, remote_stats.packets + 1);
  766.             timeouts++;
  767.             start = now;
  768.          } /* if (time( now ) > (start + M_gPacketTimeout) ) */
  769.       } /* if (!arrived[rbl] ) */
  770.    } /* while (!arrived[rbl] && i) */
  771.  
  772. #ifdef _DEBUG
  773.    debuglevel = savedebug;
  774. #endif
  775.  
  776.    if (!arrived[rbl])
  777.    {
  778.       printmsg(0,"ggetpkt: Remote host failed to respond after %ld seconds",
  779.                (long) M_gPacketTimeout * M_MaxErr);
  780.       gclosepk();
  781.       return -1;
  782.    }
  783.  
  784. /*--------------------------------------------------------------------*/
  785. /*                           Got a packet!                            */
  786. /*--------------------------------------------------------------------*/
  787.  
  788.    *len = inlen[rbl];
  789.    MEMCPY(data, inbuf[rbl], *len);
  790.  
  791.    arrived[rbl] = FALSE;      /* Buffer is now emptied               */
  792.    rwu = nextpkt(rwu);        /* bump receive window                 */
  793.  
  794.    return(0);
  795.  
  796. } /*ggetpkt*/
  797.  
  798.  
  799. /*
  800.    g s e n d p k t
  801.  
  802.    Put at most a packet's worth of data in the packet state
  803.    machine for transmission.
  804.    May have to run the packet machine a few times to get
  805.    an available output slot.
  806.  
  807.    on input: data=*data; len=length of data in data.
  808.  
  809.    return:
  810.     0 if all's well
  811.    -1 if problems (failed)
  812. */
  813.  
  814. short gsendpkt(char *data, short len)
  815. {
  816.    short delta;
  817. #ifdef _DEBUG
  818.    short savedebug = debuglevel;
  819. #endif
  820.  
  821.    checkref( data );
  822.    irec = 0;
  823.    /* WAIT FOR INPUT i.e. if weve sent SWINDOW pkts and none have been
  824.       acked, wait for acks */
  825.    while (nbuffers >= nwindows)
  826.       if (gmachine(0) != POK)    /* Spin with no timeout             */
  827.          return(-1);
  828.  
  829. /*--------------------------------------------------------------------*/
  830. /*               Place packet in table and mark unacked               */
  831. /*--------------------------------------------------------------------*/
  832.  
  833.    MEMCPY(outbuf[sbu], data, len);
  834.  
  835. /*--------------------------------------------------------------------*/
  836. /*                       Handle short packets.                        */
  837. /*--------------------------------------------------------------------*/
  838.  
  839.    xmitlen[sbu] = s_pktsize;
  840.    if (variablepacket)
  841.       while ( ((len * 2) < (short) xmitlen[sbu]) && (xmitlen[sbu] > MINPKT) )
  842.          xmitlen[sbu] /= 2;
  843.  
  844.    if ( xmitlen[sbu] < MINPKT )
  845.    {
  846.       printmsg(0,"gsendpkt: Bad packet size %d, "
  847.                "data length %d",
  848.                xmitlen[sbu], len);
  849.       xmitlen[sbu] = MINPKT;
  850.    }
  851.  
  852.    delta = xmitlen[sbu] - len;
  853.    if (delta > 127)
  854.    {
  855.       MEMMOVE(outbuf[sbu] + 2, outbuf[sbu], len);
  856.       MEMSET(outbuf[sbu]+len+2, 0, delta - 2);
  857.                               /* Pad with nulls.  Ugh.               */
  858.       outbuf[sbu][0] = (unsigned char) ((delta & 0x7f) | 0x80);
  859.       outbuf[sbu][1] = (unsigned char) (delta >> 7);
  860.    } /* if (delta > 127) */
  861.    else if (delta > 0 )
  862.    {
  863.       MEMMOVE(outbuf[sbu] + 1, outbuf[sbu], len);
  864.       outbuf[sbu][0] = (unsigned char) delta;
  865.       MEMSET(outbuf[sbu]+len+1, 0, delta - 1);
  866.                               /* Pad with nulls.  Ugh.               */
  867.    } /* else if (delta > 0 )  */
  868.  
  869. /*--------------------------------------------------------------------*/
  870. /*                            Mark packet                             */
  871. /*--------------------------------------------------------------------*/
  872.  
  873.    outlen[sbu] = len;
  874.    ftimer[sbu] = time(nil(long));
  875.    nbuffers++;
  876.  
  877. /*--------------------------------------------------------------------*/
  878. /*                              send it                               */
  879. /*--------------------------------------------------------------------*/
  880.  
  881.    gspack(DATA, rwl, swu, outlen[sbu], xmitlen[sbu], outbuf[sbu]);
  882.  
  883.    swu = nextpkt(swu);        /* Bump send window                    */
  884.    sbu = nextbuf( sbu );      /* Bump to next send buffer            */
  885.  
  886. #ifdef _DEBUG
  887.    debuglevel = savedebug;
  888. #endif
  889.  
  890.    return(0);
  891.  
  892. } /*gsendpkt*/
  893.  
  894.  
  895. /*--------------------------------------------------------------------*/
  896. /*    g e o f p k t                                                   */
  897. /*                                                                    */
  898. /*    Transmit EOF to the other system                                */
  899. /*--------------------------------------------------------------------*/
  900.  
  901. short geofpkt( void )
  902. {
  903.    if (gsendpkt("", 0))          /* Empty packet == EOF              */
  904.       return FAILED;
  905.    else
  906.       return OK;
  907. } /* geofpkt */
  908.  
  909. /*--------------------------------------------------------------------*/
  910. /*    g w r m s g                                                     */
  911. /*                                                                    */
  912. /*    Send a message to remote system                                 */
  913. /*--------------------------------------------------------------------*/
  914.  
  915. short gwrmsg( char *s )
  916. {
  917.    for(; strlen(s) >= s_pktsize; s += s_pktsize) {
  918.       short result = gsendpkt(s, s_pktsize);
  919.       if (result)
  920.          return result;
  921.    }
  922.  
  923.    return gsendpkt(s, strlen(s)+1);
  924. } /* gwrmsg */
  925.  
  926. /*--------------------------------------------------------------------*/
  927. /*    g r d m s g                                                     */
  928. /*                                                                    */
  929. /*    Read a message from the remote system                           */
  930. /*--------------------------------------------------------------------*/
  931.  
  932. short grdmsg( char *s)
  933. {
  934.    for ( ;; )
  935.    {
  936.       short len;
  937.       short result = ggetpkt( s, &len );
  938.       if (result || (s[len-1] == '\0'))
  939.          return result;
  940.       s += len;
  941.    } /* for */
  942.  
  943. } /* grdmsg */
  944.  
  945. /**********  Packet Machine  ********** RH Lamb 3/87 */
  946.  
  947. /*--------------------------------------------------------------------*/
  948. /*    g m a c h i n e                                                 */
  949. /*                                                                    */
  950. /*    Ideally we would like to fork this process off in an            */
  951. /*    infinite loop and send and receive packets through "inbuf"      */
  952. /*    and "outbuf".  Can't do this in MS-DOS so we setup "getpkt"     */
  953. /*    and "sendpkt" to call this routine often and return only        */
  954. /*    when the input buffer is empty thus "blocking" the packet-      */
  955. /*    machine task.                                                   */
  956. /*--------------------------------------------------------------------*/
  957.  
  958. static short gmachine(const short timeout )
  959. {
  960.    static time_t idletimer = 0;
  961.  
  962.    boolean done   = FALSE;    /* True = drop out of machine loop  */
  963.    boolean close  = FALSE;    /* True = terminate connection upon
  964.                                         exit                      */
  965.    boolean inseq  = TRUE;     /* True = Count next out of sequence
  966.                                         packet as an error           */
  967.    while ( !done )
  968.    {
  969.       boolean resend = FALSE;    /* True = resend data packets       */
  970.       boolean donak  = FALSE;    /* True = NAK the other system      */
  971.       unsigned long packet_no = remote_stats.packets;
  972.  
  973.       short pkttype, rack, rseq, rlen, rbuf, i1;
  974.       time_t now;
  975.  
  976. #ifdef UDEBUG
  977.       if ( debuglevel >= 7 )     /* Optimize processing a little bit */
  978.       {
  979.  
  980.          printmsg(10, "* send %d %d < W < %d %d, "
  981.                       "receive %d %d < W < %d, "
  982.                       "error %d, packet %d",
  983.             swl, sbl, swu, sbu, rwl, rbl, rwu, nerr,
  984.             (long) remote_stats.packets);
  985.  
  986. /*--------------------------------------------------------------------*/
  987. /*    Waiting for ACKs for swl to swu-1.  Next pkt to send=swu        */
  988. /*    rwl=expected pkt                                                */
  989. /*--------------------------------------------------------------------*/
  990.  
  991.       }
  992. #endif
  993.  
  994. /*--------------------------------------------------------------------*/
  995. /*             Attempt to retrieve a packet and handle it             */
  996. /*--------------------------------------------------------------------*/
  997.  
  998.       pkttype = grpack(&rack, &rseq, &rlen, inbuf[nextbuf(rbl)], timeout);
  999.       time(&now);
  1000.       switch (pkttype) {
  1001.  
  1002.          case CLOSE:
  1003.             remote_stats.packets++;
  1004.             printmsg(GDEBUG, "**got CLOSE");
  1005.             close = done = TRUE;
  1006.             break;
  1007.  
  1008.          case EMPTY:
  1009.             printmsg(timeout ? GDEBUG : 8, "**got EMPTY");
  1010.  
  1011.             if (bmodemflag[MODEM_CD] && !CD())
  1012.             {
  1013.                printmsg(0,"gmachine: Modem carrier lost");
  1014.                nerr++;
  1015.                close = TRUE;
  1016.             }
  1017.  
  1018.             if ( terminate_processing )
  1019.             {
  1020.                printmsg(0,"gmachine: User aborted processing");
  1021.                close = TRUE;
  1022.             }
  1023.  
  1024.             if (ftimer[sbl])
  1025.             {
  1026. #ifdef UDEBUG
  1027.                printmsg(6, "---> seq, elapst %d %ld", sbl,
  1028.                     ftimer[sbl] - now);
  1029. #endif
  1030.                if ( ftimer[sbl] <= (now - M_gPacketTimeout))
  1031.                {
  1032.                    printmsg(4, "*** timeout %d (%ld)",
  1033.                                sbl, (long) remote_stats.packets);
  1034.                        /* Since "g" is "go-back-N", when we time out we
  1035.                           must send the last N pkts in order.  The generalized
  1036.                           sliding window scheme relaxes this reqirment. */
  1037.                    nerr++;
  1038.                    timeouts++;
  1039.                    resend = TRUE;
  1040.                } /* if */
  1041.             } /* if */
  1042.  
  1043.             done = TRUE;
  1044.             break;
  1045.  
  1046.          case DATA:
  1047.             printmsg(5, "**got DATA %d %d", rack, rseq);
  1048.             i1 = nextpkt(rwl);   /* (R+1)%8 <-- -->(R+W)%8 */
  1049.             if (i1 == rseq) {
  1050.                lazynak--;
  1051.                remote_stats.packets++;
  1052.                idletimer = now;
  1053.                rwl = i1;
  1054.                rbl = nextbuf( rbl );
  1055.                inseq = arrived[rbl] = TRUE;
  1056.                inlen[rbl] = rlen;
  1057.                printmsg(5, "*** ACK d %d %d", rwl, rbl);
  1058.                gspack(ACK, rwl, 0, 0, 0, NULL);
  1059.                done = TRUE;   /* return to caller when finished      */
  1060.                               /* in a mtask system, unneccesary      */
  1061.             } else {
  1062.                if (inseq || ( now > (idletimer + M_gPacketTimeout)))
  1063.                {
  1064.                   donak = TRUE;  /* Only flag first out of sequence
  1065.                                     packet as error, since we know
  1066.                                     following ones also bad             */
  1067.                   outsequence++;
  1068.                   inseq = FALSE;
  1069.                }
  1070.                printmsg(GDEBUG, "*** unexpect %d ne %d (%d - %d)",
  1071.                                        rseq, i1, rwl, rwu);
  1072.             } /* else */
  1073.  
  1074.             if ( swl == swu )       /* We waiting for an ACK?     */
  1075.                break;               /* No --> Skip ACK processing */
  1076.             /* else Fall through to ACK case */
  1077.  
  1078.          case NAK:
  1079.          case ACK:
  1080.             if (pkttype == NAK)
  1081.             {
  1082.                nerr++;
  1083.                naksin++;
  1084.                printmsg(5, "**got NAK %d", rack);
  1085.                resend = TRUE;
  1086.             }
  1087.             else if (pkttype == ACK)
  1088.                printmsg(5, "**got ACK %d", rack);
  1089.  
  1090.             while(between(swl, rack, swu))
  1091.             {                             /* S<-- -->(S+W-1)%8 */
  1092.                remote_stats.packets++;
  1093.                printmsg(5, "*** ACK %d", swl);
  1094.                ftimer[sbl] = 0;
  1095.                idletimer = now;
  1096.                nbuffers--;
  1097.                done = TRUE;            /* Get more data for input */
  1098.                swl = nextpkt(swl);
  1099.                sbl = nextbuf(sbl);
  1100.             } /* while */
  1101.  
  1102.             if (!done && (pkttype == ACK)) /* Find packet?         */
  1103.             {
  1104.                printmsg(GDEBUG,"*** ACK for bad packet %d (%d - %d)",
  1105.                            rack, swl, swu);
  1106.             } /* if */
  1107.             break;
  1108.  
  1109.          case ERROR:
  1110.             printmsg(GDEBUG, "*** got BAD CHK");
  1111.             naksout++;
  1112.             donak = TRUE;
  1113.             lazynak = 0;               /* Always NAK bad checksum */
  1114.             break;
  1115.  
  1116.          default:
  1117.             screwups++;
  1118.             nerr++;
  1119.             printmsg(GDEBUG, "*** got SCREW UP");
  1120.             break;
  1121.  
  1122.       } /* switch */
  1123.  
  1124. /*--------------------------------------------------------------------*/
  1125. /*      If we received an NAK or timed out, resend data packets       */
  1126. /*--------------------------------------------------------------------*/
  1127.  
  1128.       if ( resend )
  1129.       for (rack = swl,
  1130.            rbuf = sbl;
  1131.            between(swl, rack, swu);
  1132.            rack = nextpkt(rack), rbuf = nextbuf( rbuf ))
  1133.       {                          /* resend rack->(swu-1)             */
  1134.          resends++;
  1135.  
  1136.          if ( outbuf[rbuf] == NULL )
  1137.          {
  1138.             printmsg(0,"gmachine: Transmit of NULL packet (%d %d)",
  1139.                      rwl, rbuf);
  1140.             panic();
  1141.          }
  1142.  
  1143.          if ( xmitlen[rbuf] == 0 )
  1144.          {
  1145.             printmsg(0,"gmachine: Transmit of 0 length packet (%d %d)",
  1146.                      rwl, rbuf);
  1147.             panic();
  1148.          }
  1149.  
  1150.          gspack(DATA, rwl, rack, outlen[rbuf], xmitlen[rbuf], outbuf[rbuf]);
  1151.          printmsg(5, "*** resent %d", rack);
  1152.          idletimer = ftimer[rbuf] = now;
  1153.       } /* for */
  1154.  
  1155. /*--------------------------------------------------------------------*/
  1156. /*  If we have an error and have not recently sent a NAK, do so now.  */
  1157. /*  We then reset our counter so we receive at least a window full of */
  1158. /*                 packets before sending another NAK                 */
  1159. /*--------------------------------------------------------------------*/
  1160.  
  1161.       if ( donak )
  1162.       {
  1163.          nerr++;
  1164.          if ( (lazynak < 1) || (now > (idletimer + M_gPacketTimeout)))
  1165.          {
  1166.             printmsg(5, "*** NAK d %d", rwl);
  1167.             gspack(NAK, rwl, 0, 0, 0, NULL);
  1168.             naksout++;
  1169.             idletimer = now;
  1170.             lazynak = nwindows + 1;
  1171.          } /* if ( lazynak < 1 ) */
  1172.       } /* if ( donak ) */
  1173.  
  1174. /*--------------------------------------------------------------------*/
  1175. /*                   Update error counter if needed                   */
  1176. /*--------------------------------------------------------------------*/
  1177.  
  1178.       if ((close || (packet_no != remote_stats.packets)) && (nerr > 0))
  1179.       {
  1180.          printmsg(GDEBUG,"gmachine: Packet %ld had %ld errors during transfer",
  1181.                      remote_stats.packets, (long) nerr);
  1182.          remote_stats.errors += nerr;
  1183.          nerr = 0;
  1184.       }
  1185.  
  1186. /*--------------------------------------------------------------------*/
  1187. /*    If we have an excessive number of errors, drop out of the       */
  1188. /*    loop                                                            */
  1189. /*--------------------------------------------------------------------*/
  1190.  
  1191.       if (nerr >= M_MaxErr)
  1192.       {
  1193.          printmsg(0,
  1194.             "gmachine: Consecutive error limit of %d exceeded, %d total errors",
  1195.             M_MaxErr, nerr + remote_stats.errors);
  1196.          done = close = TRUE;
  1197.          gstats();
  1198.       }
  1199.    } /* while */
  1200.  
  1201. /*--------------------------------------------------------------------*/
  1202. /*    Return to caller, gracefully terminating packet machine if      */
  1203. /*    requested                                                       */
  1204. /*--------------------------------------------------------------------*/
  1205.  
  1206.    if ( close )
  1207.    {
  1208.       gspack(CLOSE, 0, 0, 0, 0, NULL);
  1209.       return CLOSE;
  1210.    }
  1211.    else
  1212.       return POK;
  1213.  
  1214. } /*gmachine*/
  1215.  
  1216.  
  1217. /*************** FRAMING *****************************/
  1218.  
  1219. /*
  1220.    g s p a c k
  1221.  
  1222.    Send a packet
  1223.  
  1224.    type=type yyy=pkrec xxx=timesent len=length<=s_pktsize data=*data
  1225.    ret(0) always
  1226. */
  1227.  
  1228. static void gspack(short type,
  1229.                    short yyy,
  1230.                    short xxx,
  1231.                    short len,
  1232.                    unsigned short xmit,
  1233. #ifdef WIN32
  1234.                    char *data)
  1235. #else
  1236.                    char UUFAR *input)
  1237. #endif
  1238. {
  1239.    unsigned short check, i;
  1240.    unsigned char header[HDRSIZE];
  1241.  
  1242. #ifndef WIN32
  1243.    char *data;                   // Local data buffer address
  1244.    if ( input == NULL )
  1245.       data = NULL;               // Make consistent with real buffer
  1246.    else {                        // Only copy if non-NULL
  1247.       data = gspkt;
  1248.       MEMCPY( data, input, xmit );
  1249.    }
  1250. #endif
  1251.  
  1252. #ifdef   LINKTEST
  1253.    /***** Link Testing Mods *****/
  1254.    unsigned char dpkerr[10];
  1255.    /***** End Link Testing Mods *****/
  1256. #endif   /* LINKTEST */
  1257.  
  1258. #ifdef   LINKTEST
  1259.    /***** Link Testing Mods - create artificial errors *****/
  1260.    printf("**n:normal,e:error,l:lost,p:partial,h:bad header,s:new seq--> ");
  1261.    gets(dpkerr);
  1262.    if (dpkerr[0] == 's')
  1263.       sscanf(&dpkerr[1], "%d", &xxx);
  1264.    /***** End Link Testing Mods *****/
  1265. #endif   /* LINKTEST */
  1266.  
  1267.    if ( debuglevel > 4 )
  1268.       printmsg(5, "send packet type %d, yyy=%d, xxx=%d, len=%d, buf = %d",
  1269.                type, yyy, xxx, len, xmit);
  1270.  
  1271.    header[0] = '\020';
  1272.    header[4] = (unsigned char) (type << 3);
  1273.  
  1274.    switch (type) {
  1275.  
  1276.       case CLOSE:
  1277.          break;   /* stop protocol */
  1278.  
  1279.       case NAK:
  1280.          header[4] += yyy;
  1281.          break;   /* reject */
  1282.  
  1283.       case SRJ:
  1284.          break;
  1285.  
  1286.       case ACK:
  1287.          header[4] += yyy;
  1288.          break;   /* ack */
  1289.  
  1290.       case INITA:
  1291.       case INITC:
  1292.          header[4] += xmit;
  1293.          break;
  1294.  
  1295.       case INITB:
  1296.          i = MINPKT;
  1297.          while( i < xmit )
  1298.          {
  1299.             header[4] ++;
  1300.             i *= 2;
  1301.          }
  1302.          break;
  1303.  
  1304.       case DATA:
  1305.          header[4] = (unsigned char) (0x80 + (xxx << 3) + yyy);
  1306.          if (len < (short) xmit)      /* Short packet?              */
  1307.             header[4] |= 0x40;/* Count byte handled at higher level */
  1308.  
  1309. #ifdef UDEBUG
  1310.             printmsg(7, "data=|%.*s|", len, data);
  1311. #endif
  1312.          break;
  1313.  
  1314.       default:
  1315.          printmsg(0,"gspack: Invalid packet type %d",type);
  1316.          panic();
  1317.    } /* switch */
  1318.  
  1319. /*--------------------------------------------------------------------*/
  1320. /*    Now we finish up the header.  For data packets, determine       */
  1321. /*    the K number in header[1], which specifies the number of        */
  1322. /*    actual data bytes transmitted as a power of 2; we also          */
  1323. /*    compute a checksum on the data.                                 */
  1324. /*--------------------------------------------------------------------*/
  1325.  
  1326.    if (type == DATA)
  1327.    {
  1328.       header[1] = 1;
  1329.       i = MINPKT;
  1330.       while( i < xmit )
  1331.       {
  1332.          header[1] ++;
  1333.          i *= 2;
  1334.       }
  1335.  
  1336.       if ( i != xmit )        /* Did it come out exact power of 2?   */
  1337.       {
  1338.          printmsg(0,"Packet length error ... %d != %d for K = %d",
  1339.                i, xmit, (int) header[1]);
  1340.          panic();             /* No --> Well, we blew THAT math      */
  1341.       } /* if ( i != xmit ) */
  1342.  
  1343. /*--------------------------------------------------------------------*/
  1344. /*                        Compute the checksum                        */
  1345. /*--------------------------------------------------------------------*/
  1346.  
  1347.       check = checksum(data, xmit);
  1348.       i = header[4]; /* got to do this on PC for ex-or high bits */
  1349.       i &= 0xff;
  1350.       check = (check ^ i) & 0xffff;
  1351.       check = (0xaaaa - check) & 0xffff;
  1352.    }
  1353.    else {
  1354.       header[1] = 9;          /* Control packet size K number (9)    */
  1355.       check = (0xaaaa - header[4]) & 0xffff;
  1356.                               /* Simple checksum for control         */
  1357.    } /* else */
  1358.  
  1359.    header[2] = (unsigned char) (check & 0xff);
  1360.    header[3] = (unsigned char) ((check >> 8) & 0xff);
  1361.    header[5] = (unsigned char)
  1362.             ((header[1] ^ header[2] ^ header[3] ^ header[4]) & 0xff) ;
  1363.  
  1364. #ifdef   LINKTEST
  1365.    /***** More Link Testing Mods *****/
  1366.    switch(dpkerr[0]) {
  1367.    case 'e':
  1368.       data[10] = - data[10];
  1369.       break;
  1370.    case 'h':
  1371.       header[5] = - header[5];
  1372.       break;
  1373.    case 'l':
  1374.       return;
  1375.    case 'p':
  1376.       swrite((char *) header, HDRSIZE);
  1377.       if (header[1] != 9)
  1378.          swrite(data, xmit - 3);
  1379.       return;
  1380.    default:
  1381.       break;
  1382.    }
  1383.    /***** End Link Testing Mods *****/
  1384. #endif   /* LINKTEST */
  1385.  
  1386.    swrite((char *) header, HDRSIZE);      /* header is 6-bytes long */
  1387.    if (header[1] != 9)
  1388.       swrite(data, xmit);
  1389.  
  1390. } /*gspack*/
  1391.  
  1392.  
  1393. /*
  1394.    g r p a c k
  1395.  
  1396.    Read packet
  1397.  
  1398.    on return: yyy=pkrec xxx=pksent len=length<=PKTSIZE  data=*data
  1399.  
  1400.    ret(type)   ok
  1401.    ret(EMPTY)  input buf empty
  1402.    ret(ERROR)  bad header
  1403.  
  1404.    ret(EMPTY)  lost packet timeout
  1405.    ret(ERROR)  checksum error
  1406.    ret(-5)     packet size != 64
  1407.  
  1408.    NOTE (specifications for sread()):
  1409.  
  1410.    sread(buf, n, timeout)
  1411.       while(TRUE) {
  1412.          if (# of chars available >= n) (without dec internal counter)
  1413.             read n chars into buf (decrement internal char counter)
  1414.             break
  1415.     else
  1416.        if (time > timeout)
  1417.           break;
  1418.       }
  1419.       return(# of chars available)
  1420.  
  1421. */
  1422.  
  1423. static short grpack(short *yyy,
  1424.                   short *xxx,
  1425.                   short *len,
  1426.                   char UUFAR *data,
  1427.                   const short timeout)
  1428. {
  1429.    static short got_hdr  = FALSE;
  1430.    static short received = 0;     /* Bytes already read into buffer */
  1431.    short needed;
  1432.  
  1433.    unsigned short type, check, checkchk, i, total = 0;
  1434.    unsigned char c, c2;
  1435.  
  1436.    time_t start;
  1437.  
  1438.    if (got_hdr)
  1439.       goto get_data;
  1440.  
  1441. /*--------------------------------------------------------------------*/
  1442. /*   Spin up to timeout waiting for a Control-P, our sync character   */
  1443. /*--------------------------------------------------------------------*/
  1444.  
  1445.    start = 0;
  1446.    while (!got_hdr)
  1447.    {
  1448.       unsigned char *psync;
  1449.  
  1450.       needed = HDRSIZE - received;
  1451.       if ( needed > 0 )       /* Have enough bytes for header?       */
  1452.       {                       /* No --> Read as much as we need      */
  1453.          short wait;
  1454.  
  1455.          if ( start == 0 )    /* First pass through data?            */
  1456.          {                    /* Yes --> Set timers up               */
  1457.             start = time(nil(time_t));
  1458.             wait = timeout;
  1459.          } /* if ( start == 0 ) */
  1460.          else {
  1461.             wait = (short) (time(NULL) - start) - timeout;
  1462.             if (wait < 0)     /* Negative timeout?                   */
  1463.                wait = 0;      /* Make it no time out                 */
  1464.          } /* else */
  1465.  
  1466.          if (sread((char *) &grpkt[received], needed, wait ) <
  1467.              (unsigned short) needed )
  1468.                               /* Did we get the needed data?         */
  1469.             return EMPTY;     /* No --> Return to caller             */
  1470.  
  1471.          received += needed;
  1472.       } /* if ( needed < received ) */
  1473.  
  1474. /*--------------------------------------------------------------------*/
  1475. /*            Search for sync character in newly read data            */
  1476. /*--------------------------------------------------------------------*/
  1477.  
  1478. #ifdef UDEBUG
  1479.       printmsg(10,"grpack: Have %d characters after reading %d",
  1480.                received, needed);
  1481. #endif
  1482.  
  1483.       psync = memchr( grpkt, '\020', received );
  1484.       if ( psync == NULL )    /* Did we find the sync character?     */
  1485.          received = 0;        /* No --> Reset to empty buffer        */
  1486.       else if ( psync != grpkt ) /* First character in buffer?       */
  1487.       {                       /* No --> Make it first character      */
  1488.          received -= psync - grpkt;
  1489.          shifts++;
  1490.          memmove( grpkt, psync, received );
  1491.                               /* Shift buffer over                   */
  1492.       } /* else */
  1493.  
  1494. /*--------------------------------------------------------------------*/
  1495. /*    If we have read an entire packet header, then perform a         */
  1496. /*    simple XOR checksum to determine if it is valid.  If we have    */
  1497. /*    a valid checksum, drop out of this search, else drop the        */
  1498. /*    sync character and restart the scan.                            */
  1499. /*--------------------------------------------------------------------*/
  1500.  
  1501.       if ( received >= HDRSIZE )
  1502.       {
  1503.          i = (unsigned short) (grpkt[1] ^ grpkt[2] ^ grpkt[3] ^
  1504.                         grpkt[4] ^ grpkt[5]);
  1505.          i &= 0xff;
  1506.          printmsg(i ? 2 : 10, "prpkt %02x %02x %02x %02x %02x .. %02x ",
  1507.             grpkt[1], grpkt[2], grpkt[3], grpkt[4], grpkt[5], i);
  1508.  
  1509.          if (i == 0)          /* Good header?                        */
  1510.             got_hdr = TRUE;   /* Yes --> Drop out of loop            */
  1511.          else {               /* No  --> Flag it, continue loop      */
  1512.             badhdr++;
  1513.             printmsg(GDEBUG, "*** bad pkt header ***");
  1514.             memmove( grpkt, &grpkt[ 1 ], --received );
  1515.                               /* Begin scanning for sync character
  1516.                                  with next byte                      */
  1517.          } /* else */
  1518.       } /* if ( received > HDRSIZE ) */
  1519.    } /* while */
  1520.  
  1521. /*--------------------------------------------------------------------*/
  1522. /*                       Handle control packets                       */
  1523. /*--------------------------------------------------------------------*/
  1524.  
  1525.    if (grpkt[1] == 9)
  1526.    {
  1527.       if ( data != NULL )
  1528.          *data = '\0';
  1529.       *len = 0;
  1530.       c = grpkt[4];
  1531.       type = c >> 3;
  1532.       *yyy = c & 0x07;
  1533.       *xxx = 0;
  1534.       check = 0;
  1535.       checkchk = 0;
  1536.       got_hdr = FALSE;
  1537.    }
  1538.  
  1539. /*--------------------------------------------------------------------*/
  1540. /*                        Handle data packets                         */
  1541. /*--------------------------------------------------------------------*/
  1542.    else {
  1543. get_data:
  1544.       if ( data == NULL )
  1545.       {
  1546.          printmsg(0,"grpack: Unexpected data packet!");
  1547.          received = 0;
  1548.          return(ERROR);
  1549.       }
  1550.  
  1551. /*--------------------------------------------------------------------*/
  1552. /*             Compute the size of the data block desired             */
  1553. /*--------------------------------------------------------------------*/
  1554.  
  1555.       total = 8 * (2 << grpkt[1]);
  1556.       if (total > r_pktsize)  /* Within the defined limits?          */
  1557.       {                       /* No --> Other system has bad header,
  1558.                                  or the header got corrupted         */
  1559.          printmsg(0,"grpack: Invalid packet size %d (%d)",
  1560.             total, (int) grpkt[1]);
  1561.          received = 0;
  1562.          got_hdr = FALSE;
  1563.          return(ERROR);
  1564.       }
  1565.  
  1566.       needed = total + HDRSIZE - received;
  1567.                                  /* Compute byte required to fill
  1568.                                     data buffer                      */
  1569.  
  1570. /*--------------------------------------------------------------------*/
  1571. /*     If we don't have enough data in the buffer, read some more     */
  1572. /*--------------------------------------------------------------------*/
  1573.  
  1574.       if ((needed > 0) &&
  1575.           (sread((char *) &grpkt[HDRSIZE+total-needed], needed, timeout) <
  1576.            (unsigned short)needed))
  1577.          return(EMPTY);
  1578.  
  1579.       got_hdr = FALSE;           /* Must re-process header next pass */
  1580.  
  1581. /*--------------------------------------------------------------------*/
  1582. /*              Break packet header into various values               */
  1583. /*--------------------------------------------------------------------*/
  1584.  
  1585.       type = 0;
  1586.       c2 = grpkt[4];
  1587.       c = (unsigned char) (c2 & 0x3f);
  1588.       *xxx = c >> 3;
  1589.       *yyy = c & 0x07;
  1590.       i = grpkt[3];
  1591.       i = (i << 8) & 0xff00;
  1592.       check = grpkt[2];
  1593.       check = i | (check & 0xff);
  1594.       checkchk = checksum( (char *) grpkt + HDRSIZE , total);
  1595.       i = grpkt[4] | 0x80;
  1596.       i &= 0xff;
  1597.       checkchk = 0xaaaa - (checkchk ^ i);
  1598.       checkchk &= 0xffff;
  1599.       if (checkchk != check)
  1600.       {
  1601.          printmsg(4, "*** checksum error ***");
  1602.          memmove( grpkt, grpkt + HDRSIZE, total );
  1603.                               /* Save data so we can scan for sync   */
  1604.          received = total;    /* Note the amount of the data in buf  */
  1605.          return(ERROR);       /* Return to caller with error         */
  1606.       }
  1607.  
  1608. /*--------------------------------------------------------------------*/
  1609. /*    The checksum is correct, now determine the length of the        */
  1610. /*    data to return.                                                 */
  1611. /*--------------------------------------------------------------------*/
  1612.  
  1613.       *len = total;
  1614.  
  1615.       if (c2 & 0x40)
  1616.       {
  1617.          short ii;
  1618.          if ( grpkt[HDRSIZE] & 0x80 )
  1619.          {
  1620.             ii = (grpkt[HDRSIZE] & 0x7f) + ((grpkt[HDRSIZE+1] & 0xff) << 7);
  1621.             *len -= ii;
  1622.             MEMCPY(data, grpkt + HDRSIZE + 2, *len);
  1623.          }
  1624.          else {
  1625.             ii = (grpkt[HDRSIZE] & 0xff);
  1626.             *len -= ii;
  1627.             MEMCPY(data, grpkt + HDRSIZE + 1, *len);
  1628.          } /* else */
  1629.       }
  1630.       else
  1631.          MEMCPY( data, grpkt + HDRSIZE, *len);
  1632.    } /* else */
  1633.  
  1634. /*--------------------------------------------------------------------*/
  1635. /*           Announce what we got and return to the caller            */
  1636. /*--------------------------------------------------------------------*/
  1637.  
  1638.    received = 0;              /* Returning entire buffer, reset count */
  1639.    printmsg(5, "receive packet type %d, yyy=%d, xxx=%d, len=%d",
  1640.       type, *yyy, *xxx, *len);
  1641.  
  1642. #ifdef UDEBUG
  1643.    printmsg(13, " checksum rec=%04x comp=%04x\ndata=|%.*s|",
  1644.       check, checkchk, total, grpkt + HDRSIZE);
  1645. #endif
  1646.  
  1647.    return(type);
  1648.  
  1649. } /*grpack*/
  1650.  
  1651.  
  1652. /*
  1653.    c h e c k s u m
  1654. */
  1655.  
  1656. static unsigned short checksum(char *data, short len)
  1657. {
  1658.    short i, j;
  1659.    unsigned short tmp, chk1, chk2;
  1660.    chk1 = 0xffff;
  1661.    chk2 = 0;
  1662.    j = len;
  1663.    for (i = 0; i < len; i++) {
  1664.       if (chk1 & 0x8000) {
  1665.          chk1 <<= 1;
  1666.          chk1++;
  1667.       } else {
  1668.          chk1 <<= 1;
  1669.       }
  1670.       tmp = chk1;
  1671.       chk1 += (data[i] & 0xff);
  1672.       chk2 += chk1 ^ j;
  1673.       if ((chk1 & 0xffff) <= (tmp & 0xffff))
  1674.          chk1 ^= chk2;
  1675.       j--;
  1676.    }
  1677.    return(chk1 & 0xffff);
  1678.  
  1679. } /*checksum*/
  1680.